fig-financial-payments-b2b-xapi

(0 reviews)

Encrypting the Payment Payload

Introduction

Certain financial operations require additional security controls when transmitting sensitive customer and transaction data.

For that reason, the Payments API provides a dedicated encrypted submission endpoint.

Instead of sending the MB WAY payment details as a JSON body, your application must:

  1. Build the JSON object according to the contractCreateMbWayIntentBackendRequest
  2. Encrypt the JSON using AES-256/GCM
  3. Send:
  4. The ciphertext in the HTTP body
  5. The IV (X-IV) and AuthTag (X-AuthTag) in the headers

    • The X-Receipt-Token previously obtained from the provisional receipt flow

This ensures that sensitive customer data remains encrypted end-to-end.


How Encryption Works

When your system executes the insurance contracting process, the Financial Platform returns:

  • receiptToken – an opaque token that must be returned unchanged when initiating the payment
  • encryptionKey – a Base64-encoded AES-256 key used only for this payment flow

You will use this encryptionKey to encrypt the payment intent payload before submitting it to the encrypted endpoint.

Encryption Algorithm

The encryption process uses the following standards:

  • AES-256 in GCM mode
  • 12-byte IV (NIST recommendation for GCM)
  • 128-bit authentication tag
  • Base64 encoding for all encrypted components

GCM mode ensures both confidentiality and integrity (tamper detection).


What You Must Encrypt

The plaintext JSON must follow exactly the structure described in:

pay-lib.CreateMbWayIntentBackendRequest

This is the full MB WAY payment intent payload:

amount breakdown, payment key, customer details, vouchers, metadata, etc.

Only the transport changes β€” the JSON schema remains the same.

After building this JSON object, encrypt it and send only the Base64 ciphertext.


Request Structure for Encrypted Submission

Required HTTP Headers

HeaderDescription
X-Receipt-TokenToken provided during the provisional receipt process. Must be returned exactly as received.
X-IVBase64-encoded AES-GCM Initialization Vector used during encryption.
X-AuthTagBase64-encoded AES-GCM authentication tag generated during encryption.
Idempotency-KeyUUID v4 ensuring safe retries without duplicated payments.
AuthorizationOAuth2 Client Credentials (Bearer token).

HTTP Body

The entire body must be the Base64-encoded ciphertext produced by AES-GCM.

Example: BEm45DWVy4/7cVsrEgGP6XZGaCnZUcLotXgu70lXXFbeKSak1QMPKejnZ17yFgLmAJscuAf4o7Y=

No JSON wrapper or additional fields are allowed.


Java Example (Reference Implementation)

It demonstrates how to:

  • Load the encryptionKey
  • Build a valid JSON according to the schema
  • Encrypt the JSON using AES-256/GCM
  • Extract IV, AuthTag, and Ciphertext
  • Map values to:
    • X-IV
    • X-AuthTag
    • request body (ciphertext)

Below is an example implementation showing how to encrypt the MB WAY payment payload

before sending it to the encrypted endpoint /intents/mbway.

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;

public class AesGcmEncryptor {

    public static class EncryptionResult {
        public String iv;
        public String authTag;
        public String ciphertext;
    }

    public static EncryptionResult encrypt(String plainText, String base64Key) throws Exception {

        byte[] key = Base64.getDecoder().decode(base64Key);
        SecretKeySpec secretKey = new SecretKeySpec(key, "AES");

        // GCM requires a 12-byte IV (96 bits)
        byte[] iv = new byte[12];
        new SecureRandom().nextBytes(iv);

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        // 128-bit authentication tag
        GCMParameterSpec spec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);

        byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));

        // ciphertext + authTag are concatenated β†’ split last 16 bytes
        int tagLen = 16;
        byte[] cipherBytes = new byte[encrypted.length - tagLen];
        byte[] tagBytes = new byte[tagLen];

        System.arraycopy(encrypted, 0, cipherBytes, 0, cipherBytes.length);
        System.arraycopy(encrypted, cipherBytes.length, tagBytes, 0, tagLen);

        EncryptionResult result = new EncryptionResult();
        result.iv = Base64.getEncoder().encodeToString(iv);
        result.authTag = Base64.getEncoder().encodeToString(tagBytes);
        result.ciphertext = Base64.getEncoder().encodeToString(cipherBytes);

        return result;
    }

    public static void main(String[] args) throws Exception {


        // Encryption key provided by the provisionalReceipt response
        String encryptionKey = "<BASE64_ENCRYPTION_KEY>";

        // JSON payload properly escaped for Java string literal  (must follow CreateMbWayIntentBackendRequest)
        String payload = "{\n" +
                "  \"amount\": {\n" +
                "    \"gross\": {\n" +
                "      \"value\": \"513.6\",\n" +
                "      \"currency\": \"EUR\"\n" +
                "    },\n" +
                "    \"net\": {\n" +
                "      \"value\": \"513.6\",\n" +
                "      \"currency\": \"EUR\"\n" +
                "    }\n" +
                "  },\n" +
                "  \"paymentKey\": {\n" +
                "    \"phoneNumber\": \"916486353\",\n" +
                "    \"description\": \"Pagamentos de serviΓ§o Fidelidade\"\n" +
                "  },\n" +
                "  \"customer\": {\n" +
                "    \"fullName\": \"Maria Silva\",\n" +
                "    \"email\": \"maria.silva@example.com\",\n" +
                "    \"phoneNumber\": \"916486353\",\n" +
                "    \"fiscalNumber\": \"272353167\"\n" +
                "  },\n" +
                "  \"metadata\": {\n" +
                "    \"applicationId\": \"3b2c986c-882a-4298-b369-a20ff8ee3c79\"\n" +
                "  }\n" +
                "}";

        EncryptionResult enc = encrypt(payload, encryptionKey);

        System.out.println("IV: " + enc.iv);
        System.out.println("AuthTag: " + enc.authTag);
        System.out.println("Ciphertext: " + enc.ciphertext);
    }
}

The logic can be replicated in any language supporting AES-GCM (Node.js, .NET, Python, Go, etc.).


Best Practices

  • Always generate a new IV and AuthTag for every encryption operation.
  • Do not attempt to read, modify, or decode the X-Receipt-Token.
  • Validate your JSON against the schema before encrypting.
  • Use the same Idempotency-Key when retrying the exact same encrypted payload.
  • Never send plaintext payment data to the encrypted endpoint.

Reviews